(() => {
    /**
     * function 函数声明
     */

    function sum0(x: number, y: number) {
        return x + y
    }

    console.log(sum0(1, 2));


    function sum1(x: number, y: number): number {
        return Number(x) + Number(y)
    }

    console.log(sum1(2, 3));


    /**
     * 函数表达式, 函数表达式是长这个样子的.
     * 注意: ts中的'=>'和Es6中的‘=>’意思是不一样的, ts中的‘=>’左边是参数, 括号括起来, 右边是返回值类型, Es6中的=> 是箭头函数, 表示的返回值.可以代替大扩号进行使用, 其具备了return的功能.
     */

    let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
        return x + y
    }

    let add=(num1:number,num2:number): number=>{
        return num1+num2
    }


    // 接口中的属性有四种:
    //  1. 普通变量属性, 2. 可选属性‘?’ 3. 任意属性[propName:string]:any, 4. 只读属性 readonly, 这里的只读是, 只可以在对西那个初始化的时候, 对该属性进行赋值,不是对变量的初始化.

    /**
     * 函数的声明和函数的使用, 函数从名称到函数的参数, 到函数的返回值, 到函数的调用.
     *
     */
    // 普通函数
    function fun1(name: string, age: Number): string {
        // 这里的name, age是必需传进来的
        return `name: ${name}, age is ${age}`
    }

    // 带省略值函数
    function fun2(name: string, age?: Number): string {
        // 这里的name是必需, age不能是必需
        const result = age ? `name: ${name}, age is ${age}` : `name: ${name}`
        return result
    }

    // 剩余参数函数
    function fun3(name: string, age: number, ...rest) {
        const result = age ? `name: ${name}, age is ${age}` : `name: ${name}`
        // 这里能把所有的rest参数都打印出来
        console.log('rest', rest)
        return result
    }

    fun3('bob', 12, 1, 2, 3, [89, 90, '12'])

    /**
     * 重载: 方法名相同, 参数, 返回值不同的方法, 叫重载.
     */

    // function reverse(x: number): number;
    // function reverse(x: string): string;
    function reverse(x: number | string): number | string {
        if (typeof x === 'number') {
            return Number(x.toString().split('').reverse().join(''));
        } else if (typeof x === 'string') {
            return x.split('').reverse().join('');
        }
    }

    console.log(reverse(12));
    console.log(reverse('21'));


    /**
     * 断言: 断言有两种方式, 1. as 2. <类型>值
     *  在类型断言中, 我们养成 as 的习惯, 因为react等框架也是使用这个东西的.
     */
    interface Cat {
        name: string;
        run(): void;
    }
    interface Fish {
        name: string;
        swim(): void;
    }

    function isFish(animal: Cat | Fish) {
        // 这里就会报错了, 因为, 无法判断这里的animal是cat还是Fish, 所以会bc.

        /**
         * 这里的代码会有问题的.
         */
        // if (typeof animal.swim === 'function') {
        //     // 如下的代码就不会有问题了
        //     return true;
        // }

        // 就是用断言的做法, 可以实现.
        if(typeof (animal as Fish).swim === 'function'){
            (animal as Fish).swim()
            return true
        }else {
            return false
        }
        return false;
    }

    // 如果这里是鱼, 那么就会调用这个方法;
    let fish:Fish = {
        name : 'fish',
        swim:()=>{console.log('我是鱼, 我是鱼, 我是鱼');
        }
    }

    console.log(isFish(fish));

    // swim方法
    function swim(animal:Cat | Fish) {
        // 断言如果是Fish, 他就有swim()的方法.
        (animal as Fish).swim()
    }

    // 断言就是告诉编译器, 我知道自己在干什么, 不用你来判断.
    // 对象继承了接口, 要完全实现她的普通变量和方法, 可选和任意的可以不用管.


    class ApiError extends Error {
        code:number = 0;
    }

    class HttpError extends Error {
        code:number = 500;
    }

    // 白瞎了, 初始化codeNumber没啥用.
    function isApiError(error:Error) {
        if( typeof (error as ApiError).code === 'number'){
            return true
        }
        return false
    }




})()



